package com.zenchn.utils;



/**
 * CidrIpRouter : ip CIDR工具类  研究性代码
 *
 * @author dingxinfa
 * @date 2018-09-10
 */
public class CidrIpRouter {


    /**
     * 判断是否是 cidrIp
     *
     * @param cidrIp 例如：x.x.x.x/n
     * @return 如果是返回true, 否则返回false
     */
    public static Integer isCidrIp(String cidrIp) throws Exception{

        if (cidrIp == null || "".equals(cidrIp.trim())) {
            throw new RuntimeException("[" + cidrIp + "]参数格式不正确，CIDR地址部分为空");
        }
        String[] ipIds = cidrIp.split("/");
        if (ipIds.length != 2) {
            throw new RuntimeException("[" + cidrIp + "]参数格式不正确，CIDR地址格式不正确，正确格式为x.x.x.x/n");
        }
        int num = Integer.parseInt(ipIds[1]);
        if (num > 32 || num < 4) {
            throw new RuntimeException("[" + cidrIp + "]参数格式不正确，CIDR地址格式不正确，网络ID值必须在（4,32）范围内");
        }
        return num;
    }



    /**
     * 判断是否在给定的范围内
     *
     * @param ip     判断的IP
     * @param cidrIp 例如：x.x.x.x/n
     * @return 如果是返回true, 否则返回false
     */
    public static boolean isInCidrIpRange(String ip, String cidrIp) {
        try {
            long judgeIp = ipToNumeric(ip);
            Long[] ipRange = getCidrIpRange(cidrIp);
            if (ipRange.length == 2) {
                return (judgeIp >= ipRange[0]) && (judgeIp <= ipRange[1]);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 初始化CIDR IP范围
     *
     * @param cidrIp 例如：x.x.x.x/n
     * @return
     */
    public static Long[] getCidrIpRange(String cidrIp) throws Exception {
        int num = isCidrIp(cidrIp);
        String networkId = getNetworkId(cidrIp);
        String maxIpAddres = getMaxIpAddres(networkId, getMaskRevert(num));

        Long[] ipRange = new Long[2];
        ipRange[0] = ipToNumeric(networkId);
        ipRange[1] = ipToNumeric(maxIpAddres);

        return ipRange;
    }

    /**
     * 获取网络ID，即也是CIDR表示的最小IP
     *
     * @param ipCidr CIDR法表示的IP，例如：172.16.0.0/12
     * @return 网络ID，即也是CIDR表示的最小IP
     */
    public static String getNetworkId(String ipCidr) {
        String[] ipMaskLen = ipCidr.split("\\/");
        String mask = getMask(Integer.parseInt(ipMaskLen[1]));
        String[] ips = ipMaskLen[0].split("\\.");
        String[] masks = mask.split("\\.");
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            sb.append(Integer.parseInt(ips[i]) & Integer.parseInt(masks[i]));
            if (i != 3) {
                sb.append(".");
            }
        }
        return sb.toString();
    }

    /**
     * 获取掩码
     * @param maskLength 网络ID位数
     * @return
     */
    public static String getMask(int maskLength) {
        int binaryMask = 0xFFFFFFFF << (32 - maskLength);
        StringBuilder sb = new StringBuilder();
        for (int shift = 24; shift > 0; shift -= 8) {
            sb.append(Integer.toString((binaryMask >>> shift) & 0xFF));
            sb.append(".");
        }
        sb.append(Integer.toString(binaryMask & 0xFF));
        return sb.toString();
    }

    /**
     * 获取IP最大值
     *
     * @param netId       网络ID
     * @param maskReverse 掩码反码
     * @return
     */
    public static String getMaxIpAddres(String netId, String maskReverse) {
        String[] netIdArray = netId.split("\\.");
        String[] maskRevertArray = maskReverse.split("\\.");
        StringBuilder sb = new StringBuilder();
        for (int i = 0, len = netIdArray.length; i < len; i++) {
            sb.append(Integer.parseInt(netIdArray[i]) + Integer.parseInt(maskRevertArray[i]));
            if (i != len - 1) {
                sb.append(".");
            }
        }
        return sb.toString();
    }

    /**
     * 获取掩码整型数组
     *
     * @param maskLength 网络ID位数
     * @return
     */
    public static int[] getmaskArray(int maskLength) {
        int binaryMask = 0xFFFFFFFF << (32 - maskLength);
        int[] mask = new int[4];
        for (int shift = 24, k = 0; shift > 0; shift -= 8) {
            mask[k] = (binaryMask >>> shift) & 0xFF;
            k++;
        }
        mask[3] = binaryMask & 0xFF;
        return mask;
    }

    /**
     * 获取掩码的反码
     *
     * @param maskLength 网络ID位数
     * @return
     */
    public static String getMaskRevert(int maskLength) {
        int binaryMask = 0xFFFFFFFF << (32 - maskLength);
        binaryMask = ~binaryMask;
        StringBuilder sb = new StringBuilder(15);
        for (int shift = 24; shift > 0; shift -= 8) {
            sb.append(Integer.toString((binaryMask >>> shift) & 0xFF));
            sb.append(".");
        }
        sb.append(Integer.toString(binaryMask & 0xFF));
        return sb.toString();
    }


    /**
     * IP地址转换为一个256进制的long整数
     *
     * @param ip
     * @return
     */
    public static long ipToNumeric(String ip) {
        String[] ips = ip.split("\\.");
        Long[] ipLong = new Long[4];
        for (int i = 0, len = ips.length; i < len; i++) {
            ipLong[i] = Long.parseLong(ips[i]);
        }
        long result = ipLong[3] & 0xFF;
        result |= ((ipLong[2] << 8)) & 0xFF00;
        result |= ((ipLong[1] << 16)) & 0xFF0000;
        result |= ((ipLong[0] << 24)) & 0xFF000000;
        return result;
    }




    /**
     * @param args
     */
    public static void main(String[] args) {


        String ip="192.168.1.121";
        String cidrIp = "0.0.0.0/0";


        String networkId=getNetworkId(cidrIp);

        System.out.println("NetworkId:"+networkId);
        System.out.println("MaxIp:"+getMaxIpAddres(networkId, getMaskRevert(Integer.parseInt(cidrIp.split("\\/")[1]))));

        System.out.println(isInCidrIpRange(ip,cidrIp));
    }


}
